using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using NPlot;
using TAAlert.BackTest;
using TALoaders;

namespace TAAlert.Charting
{
    public partial class StrategyChartGUI : Form
    {
        private DataTable dTableM;

        public StrategyChartGUI(string ticker, StrategyName strategy, QuoteType sigType, DataTable dTable)
        {
            this.dTableM = dTable;
            InitializeComponent();
            this.Text = strategy.ToString() + " Strategy chart for " + ticker;

            // --> Set-up Price Surface Chart
            this.priceSurfaceM.Add(new Grid(), PlotSurface2D.XAxisPosition.Bottom, PlotSurface2D.YAxisPosition.Left);

            //      Open-High-Low-Close
            this.createOHLC(this.priceSurfaceM, ticker);
            //      Signal Line
            if (sigType == QuoteType.AvgHL || sigType == QuoteType.AvgHLC)
                this.addLineChart(this.priceSurfaceM, StrategyDetail.DATE_COL, sigType.ToString(), sigType.ToString(), Color.DarkBlue, 1);
            this.addTradeSignals();
            //      Properties
            this.setUpPriceSurfaceProperties();

            // --> Set-up Grid on Extra Info Surface 
            this.extraInfoSurfaceM.Add(new Grid(), PlotSurface2D.XAxisPosition.Bottom, PlotSurface2D.YAxisPosition.Left);
            this.extraInfoSurfaceM.RightMenu = NPlot.Windows.PlotSurface2D.DefaultContextMenu;

            // --> Set-up Performance Surface
            Grid perfGrid = new Grid();
            perfGrid.HorizontalGridType = Grid.GridType.Fine;
            this.perfSurfaceM.Add(perfGrid, PlotSurface2D.XAxisPosition.Bottom, PlotSurface2D.YAxisPosition.Left);
            this.perfSurfaceM.RightMenu = NPlot.Windows.PlotSurface2D.DefaultContextMenu;
            this.createPerformanceChart(this.perfSurfaceM);
        }

        public void createVEMACharts(int n1, int n2)
        {
            // Add EMA lines to Price Chart
            string ema1Label = "Ema(" + n1.ToString() + ")";
            string ema2Label = "Ema(" + n2.ToString() + ")";

            if (n1 > 0)
                this.addLineChart(this.priceSurfaceM, StrategyDetail.DATE_COL, StrategyDetail.EMA_1_COL, ema1Label, Color.Firebrick, 1);
            if (n2 > 0)
                this.addLineChart(this.priceSurfaceM, StrategyDetail.DATE_COL, StrategyDetail.EMA_2_COL, ema2Label, Color.DodgerBlue, 2);

            // Volatility Chart to Extra Info
            this.addLineChart(this.extraInfoSurfaceM, StrategyDetail.DATE_COL, StrategyDetail.VOLATILITY_COL, "Vol", Color.DeepSkyBlue, 1);
            this.extraInfoSurfaceM.YAxis1.Label = "Volatility";
            this.extraInfoSurfaceM.YAxis1.NumberFormat = "{0:########.#%}";
        }

        public void createEMACharts(int n)
        {
            // EMA to Price chart
            string emaLabel = "Ema(" + n + ")";
            this.addLineChart(this.priceSurfaceM, StrategyDetail.DATE_COL, StrategyDetail.EMA_COL, emaLabel, Color.Firebrick, 2);
            // Volume into ExtraInfo
            this.addLineChart(this.extraInfoSurfaceM, StrategyDetail.DATE_COL, StrategyDetail.VOLUME_COL, "Volume", Color.DeepSkyBlue, 1);
            //this.extraInfoSurfaceM.XAxis1.Label = "Date";
            this.extraInfoSurfaceM.YAxis1.Label = "Volume";
            this.extraInfoSurfaceM.YAxis1.NumberFormat = "{0:0E0}";
        }

        public void createTwoEMACharts(int n1, int n2)
        {
            // Add EMA lines to Price Chart
            string ema1Label = "Ema(" + n1.ToString() + ")";
            string ema2Label = "Ema(" + n2.ToString() + ")";
            this.addLineChart(this.priceSurfaceM, StrategyDetail.DATE_COL, StrategyDetail.EMA_SHORT_COL, ema1Label, Color.Firebrick, 1);
            this.addLineChart(this.priceSurfaceM, StrategyDetail.DATE_COL, StrategyDetail.EMA_LONG_COL, ema2Label, Color.DodgerBlue, 2);

            // Volatility Chart to Extra Info
            this.addLineChart(this.extraInfoSurfaceM, StrategyDetail.DATE_COL, StrategyDetail.VOLATILITY_COL, "Vol", Color.DeepSkyBlue, 1);
            this.extraInfoSurfaceM.YAxis1.Label = "Volatility";
            this.extraInfoSurfaceM.YAxis1.NumberFormat = "{0:########.#%}";
        }

        public void createMACDCharts()
        {
            // MACD lines to Ectra Info
            this.addLineChart(this.extraInfoSurfaceM, StrategyDetail.DATE_COL, StrategyDetail.MACD_LINE_COL, "MACD Line", Color.LightGray, 1);
            this.addLineChart(this.extraInfoSurfaceM, StrategyDetail.DATE_COL, StrategyDetail.MACD_SIGNAL_COL, "MACD Signal", Color.LightSeaGreen, 1);
            this.addLineChart(this.extraInfoSurfaceM, StrategyDetail.DATE_COL, StrategyDetail.MACD_HISTOGRAM_COL, "MACD Histogram", Color.Red, 2);
            //this.extraInfoSurfaceM.XAxis1.Label = "Date";
            this.extraInfoSurfaceM.YAxis1.Label = "MACD Lines";
            this.extraInfoSurfaceM.YAxis1.NumberFormat = "{0:#.##}";
        }

        // create the common OHLC chart. Set-up axes, legend and basic properties
        private void createOHLC(NPlot.Windows.PlotSurface2D surf, string ticker)
        {
            // Price Candle Plot
            CandlePlot cPlot = new CandlePlot();
            cPlot.DataSource = this.dTableM;

            cPlot.AbscissaData = StrategyDetail.DATE_COL;
            cPlot.OpenData = StrategyDetail.OPEN_COL;
            cPlot.LowData = StrategyDetail.LOW_COL;
            cPlot.HighData = StrategyDetail.HIGH_COL;
            cPlot.CloseData = StrategyDetail.CLOSE_COL;
            cPlot.BearishColor = Color.LightPink;
            cPlot.BullishColor = Color.LightGreen;
            cPlot.Style = CandlePlot.Styles.Filled;
            cPlot.Label = ticker;
            surf.Add(cPlot, PlotSurface2D.XAxisPosition.Bottom, PlotSurface2D.YAxisPosition.Left);
        }

        private void createPerformanceChart(NPlot.Windows.PlotSurface2D surf)
        {
            // Cumulative Profit/Loss
            this.addLineChart(surf, StrategyDetail.DATE_COL, StrategyDetail.CUMUL_PL_COL, "Cum P/L", Color.DarkBlue, 3);
            // Draw-down
            this.addLineChart(surf, StrategyDetail.DATE_COL, StrategyDetail.DRAW_DOWN_COL, "DrawDown", Color.Red, 1);

            // Properties
            //surf.XAxis1.Label = "Date";
            surf.YAxis1.Label = "Wealth";

            // Legend
            Legend legend = new Legend();
            legend.AttachTo(PlotSurface2D.XAxisPosition.Top, PlotSurface2D.YAxisPosition.Left);
            legend.VerticalEdgePlacement = Legend.Placement.Inside;
            legend.HorizontalEdgePlacement = Legend.Placement.Inside;
            legend.BorderStyle = LegendBase.BorderType.Line;
            surf.Legend = legend;
        }

        // Add aline chart to an existing surface
        private void addLineChart(NPlot.Windows.PlotSurface2D surf, string xColName, string yColName, string label, Color color, int lineWidth)
        {
            LinePlot lp = new LinePlot();
            lp.DataSource = this.dTableM;

            lp.AbscissaData = xColName;
            lp.OrdinateData = yColName;
            lp.Label = label;
            lp.Color = color;
            lp.Pen.Width = lineWidth;
            surf.Add(lp, PlotSurface2D.XAxisPosition.Bottom, PlotSurface2D.YAxisPosition.Left);
        }

        private void setUpPriceSurfaceProperties()
        {
            // Axes
            this.priceSurfaceM.XAxis1.Label = "Date";
            this.priceSurfaceM.YAxis1.Label = "Price";            

            // Legend
            Legend legend = new Legend();
            legend.AttachTo(PlotSurface2D.XAxisPosition.Top, PlotSurface2D.YAxisPosition.Left);
            legend.VerticalEdgePlacement = Legend.Placement.Inside;
            legend.HorizontalEdgePlacement = Legend.Placement.Inside;
            legend.BorderStyle = LegendBase.BorderType.Line;
            this.priceSurfaceM.Legend = legend;

            // Properties
            //this.priceSurfaceM.AddInteraction(new NPlot.Windows.PlotSurface2D.Interactions.HorizontalDrag());
            //this.priceSurfaceM.AddInteraction(new NPlot.Windows.PlotSurface2D.Interactions.VerticalDrag());
            //this.priceSurfaceM.AddInteraction(new NPlot.Windows.PlotSurface2D.Interactions.AxisDrag(true));
            this.priceSurfaceM.AddInteraction(new NPlot.Windows.PlotSurface2D.Interactions.HorizontalRangeSelection());
            //this.priceSurfaceM.AddInteraction(new NPlot.Windows.PlotSurface2D.Interactions.MouseWheelZoom());

            this.priceSurfaceM.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;

            this.priceSurfaceM.RightMenu = NPlot.Windows.PlotSurface2D.DefaultContextMenu;
        }

        // Create RED/GREEN SELL/BUY signals
        private void addTradeSignals()
        {
            // BUY Signals
            List<DateTime> dBuy = new List<DateTime>();
            List<double> yBuy = new List<double>();
            List<DateTime> dSell = new List<DateTime>();
            List<double> ySell = new List<double>();
            int oldPos = 0;
            for (int rowIx = 0; rowIx < dTableM.Rows.Count; ++rowIx)
            {
                DataRow row = dTableM.Rows[rowIx];
                DateTime date = (DateTime)row[StrategyDetail.DATE_COL];
                double tradePrice = (double)row[StrategyDetail.CLOSE_COL];
                int pos = (int)row[StrategyDetail.POSITION_COL];
                if (pos > oldPos)
                {
                    dBuy.Add(date);
                    yBuy.Add(tradePrice);
                }
                if (pos < oldPos)
                {
                    dSell.Add(date);
                    ySell.Add(tradePrice);
                }
                oldPos = pos;
            }
            if (dBuy.Count > 0)
            {
                Marker buyMarker = new Marker(Marker.MarkerType.FlagUp, 10, Color.SeaGreen);
                buyMarker.Filled = true;
                PointPlot ppBuy = new PointPlot(buyMarker);
                ppBuy.AbscissaData = dBuy;
                ppBuy.OrdinateData = yBuy;
                ppBuy.ShowInLegend = false;
                this.priceSurfaceM.Add(ppBuy);

            }
            if (dSell.Count > 0)
            {
                Marker sellMarker = new Marker(Marker.MarkerType.FlagDown, 10, Color.Red);
                sellMarker.Filled = true;
                PointPlot ppSell = new PointPlot(sellMarker);
                ppSell.AbscissaData = dSell;
                ppSell.OrdinateData = ySell;
                ppSell.ShowInLegend = false;
                this.priceSurfaceM.Add(ppSell);
            }
        }

        /// <summary> When the priceSurfaceM chart has changed, this is called which updates the other charts.</summary>
        private void priceSurface_InteractionOccured(object sender)
        {
            DateTimeAxis axis = new DateTimeAxis(this.priceSurfaceM.XAxis1);
            this.extraInfoSurfaceM.XAxis1 = axis;
            this.extraInfoSurfaceM.Refresh();
            this.perfSurfaceM.XAxis1 = axis;
            this.perfSurfaceM.Refresh();
        }

    }
}